home *** CD-ROM | disk | FTP | other *** search
- ;Programmer's editor. Assemble with TASM. (C) David Nye, 1989.
-
- IDEAL
- DOSSEG
- MODEL TINY
-
- MACRO String Name, Text
- LOCAL L1
- Name db L1-Name-1, Text
- L1:
- ENDM
-
- ;Constants
- LINELENGTH EQU 80 ;Length of string storage for line
- SCREENLENGTH EQU 24 ;Number of rows in display window
- MAXLINES EQU 2000 ;Size of array of line pointers
- BUFFERLENGTH EQU 1200h ;Length of file buffer
- BELL EQU 7 ;Some non-printing chars
- BS EQU 8
- HT EQU 9
- LF EQU 10
- CR EQU 13
- CRLF EQU 0A0Dh
- CTRL_Z EQU 26
- ESCAPE EQU 27
- DEL EQU 127
- ATTRIB_NL EQU 2
- ATTRIB_INV EQU 70h
-
- DATASEG
- ;Strings
- String cantOpenMsg, "Can't open file."
- String rdErrorMsg, 'Error reading file.'
- String fileErrorMsg, 'File error.'
- String noRoomMsg, 'Out of memory.'
- String notMarkingMsg, 'Not marking.'
- String setLabelMsg, 'Label (0-9): '
- String setTabsMsg, 'Tab width: '
- String newFileMsg, 'File name: '
- String gotoMsg 'Jump to what line? '
- String editingMsg <'Help F1',186,'Editing: '>
- String findMsg 'Find: '
- String replaceMsg 'Replace with: '
- String notFoundMsg 'No more matching strings found.'
- String endHelpMsg 'Press any key to continue.'
- String ctrlCMsg '*Break*'
- String cancelledMsg 'Cancelled.'
- BAK db '.BAK', 0
- helpMsg db 'left left arrow, ^s '
- db ' mark start of block @m '
- db 'right right arrow, ^d '
- db ' copy block @c * '
- db 'word left ^left arrow, ^a '
- db ' delete block @d * '
- db 'word right ^right arrow, ^f '
- db ' insert block @i * '
- db 'start of line Home '
- db ' empty block buffer @e * '
- db 'end of line End '
- db ' unmark @u '
- db 'up up arrow, ^e '
- db 40 dup ( )
- db 'down down arrow, ^x '
- db ' find @f + '
- db 'page up PgUp, ^r '
- db ' replace @r + '
- db 'page down PgDn, ^c '
- db ' find/replace all @= + '
- db 'start of file ^PgUp '
- db 40 dup ( )
- db 'end of file ^PgDn '
- db ' save and continue @s '
- db 40 dup ( )
- db ' save and exit @x '
- db 'backspace Backspace '
- db ' kill save on exit @k '
- db 'delete Del '
- db 40 dup ( )
- db 'delete word left ^[ '
- db ' label (0-9) @l '
- db 'delete word right ^], ^t '
- db ' go to label (0-9) @g '
- db 'delete to EOL ^\ '
- db ' jump to line # @j '
- db 'delete line ^-, ^y '
- db ' set tab width @t '
- db 'undelete line ^^ '
- db ' toggle autoindent @a '
- db 'toggle insert mode Ins '
- db ' open another file @o '
- db 80 dup ( )
- db '@ = Alt, ^ = Ctrl, * = to/from file if s'
- db 'hifted, + = use last string if shifted. '
- db 'Status line flags: Insert Overwrite C'
- db 'hanged AutoInsert '
-
-
- ;Variables
- newFile? db ? ;True if new file
- inserting? db -1 ;True if in insert mode
- autoIndent? db -1 ;True if in autoindent mode
- marking? db 0 ;True if marking text
- changed? db 0 ;True if original file has been changed
- isBAKed? db 0 ;True if .BAK file already written
- justFound? db ? ;True if no other commands since last Find
- needCopies? db -1 ;True unless lines in buffer were just deleted
- autoReplace? db 0 ;-1 if auto-replace with shift, 1 without shift
- row db ? ;Current row
- column db ? ;Current column
- tabSize db 8 ;Tab increment
- fHandle dw ? ;File handle
- lastLine dw ? ;Index of last line
- top dw ? ;Index of first line on screen
- bottom dw ? ;Index of last line on screen
- bufferPtr dw ? ;Multipurpose buffer pointer
- mark dw ? ;Start of marking for block command
- here dw ? ;Temporary
- hereCol dw ? ;Temporary
- videoSegment dw ? ;Segment of system's video memory
- fName db 20 dup (?) ;File name in ASCIIZ format
- fNameBAK db 20 dup (?) ;Current file with .BAK extension added
- fNameBlock db 20 dup (?) ;File to be used in block read/writes
- pad db 20 dup (?) ;Scratch buffer
- heapStart dw ? ;Segment of start of heap
- heapPtr dw ? ;Segment pointer to next free paragraph in heap
- labelTable dw 10 dup (0) ;Table of line pointers assigned to labels
- findString dw LINELENGTH dup (?) ;Search string for Find command
- replaceString dw LINELENGTH dup (?) ;New string for Replace command
- linePtrs dw MAXLINES dup (?) ;List of line pointers
- blockPtrs dw MAXLINES dup (?) ;Line pointers for block commands
- blockPtrsLast dw OFFSET blockPtrs
- delLinePtrs dw MAXLINES dup (?) ;Line pointers for del/undel lines
- delLinePtrsLast dw OFFSET delLinePtrs
- buffer db BUFFERLENGTH dup (?) ;File and delete buffer (dual purpose)
- bufferEnd:
-
- ;Jump tables: ^ = Ctrl, @ = Alt, # = Shift.
- ctrlTable dw na ;^@
- dw WordLeft ;^A
- dw na ;^B
- dw PageDown ;^C
- dw Right ;^D
- dw Up ;^E
- dw WordRight ;^F
- dw na ;^G or BEL
- dw BackSpace ;^H or BS
- dw Tab ;^I or HT
- dw na ;^J or LF
- dw na ;^K or VT
- dw na ;^L or FF
- dw CRet ;^M or CR
- dw na ;^N or SO
- dw na ;^O or SI
- dw na ;^P
- dw na ;^Q or DC1
- dw PageUp ;^R or DC2
- dw Left ;^S or DC3
- dw DeleteWordR ;^T or DC4
- dw na ;^U
- dw na ;^V
- dw na ;^W
- dw Down ;^X or CAN
- dw DeleteLine ;^Y
- dw na ;^Z
- dw DeleteWordL ;^[ or ESC
- dw DeleteToEOL ;^\
- dw DeleteWordR ;^]
- dw UndeleteLine ;^^
- dw DeleteLine ;^-
-
- auxTable dw 15 DUP (na) ;Undefined (except for NULL = 3)
- dw ReverseTab ;#Tab
- dw na ;@Q
- dw na ;@W
- dw EmptyBuffer ;@E
- dw Replace ;@R
- dw SetTabs ;@T
- dw na ;@Y
- dw Unmark ;@U
- dw InsertBlock ;@I
- dw OtherFile ;@O
- dw na ;@P
- dw 4 DUP (na) ;Undefined
- dw AutoIndent ;@A
- dw Save ;@S
- dw DeleteBlock ;@D
- dw Find ;@F
- dw GotoLabel ;@G
- dw Help ;@H
- dw Jump ;@J
- dw Kill ;@K
- dw SetLabel ;@L
- dw 5 DUP (na) ;Undefined
- dw na ;@Z
- dw Exit ;@X
- dw Copy ;@C
- dw na ;@V
- dw na ;@B
- dw na ;@N
- dw BeginBlock ;@M
- dw 8 DUP (na) ;Undefined
- dw Help ;F1
- dw na ;F2
- dw na ;F3
- dw na ;F4
- dw na ;F5
- dw na ;F6
- dw na ;F7
- dw na ;F8
- dw na ;F9
- dw na ;F10
- dw 2 DUP (na) ;Undefined
- dw HomeLine ;Home
- dw Up ;Up arrow
- dw PageUp ;PgUp
- dw na ;Undefined
- dw Left ;Left arrow
- dw na ;Undefined
- dw Right ;Right arrow
- dw na ;Undefined
- dw EndLine ;End
- dw Down ;Down arrow
- dw PageDown ;PgDn
- dw ToggleIns ;Ins
- dw Delete ;Del
- dw 30 DUP (na) ;[#Fn, ^Fn, @Fn]
- dw na ;^PrtSc
- dw WordLeft ;^Left arrow
- dw WordRight ;^Right arrow
- dw na ;^End
- dw BottomFile ;^PgDn
- dw na ;^Home
- dw 10 DUP (na) ;[Alt numbers]
- dw na ;@-
- dw AutoReplace ;@=
- dw TopFile ;^PgUp
-
- ;******************************************************************************
-
- CODESEG
- mov ax, cs
- mov es, ax
- mov si, 80h ;Make pointer to command tail
- mov cl, [si] ;Get filename length
- sub ch, ch
- or cl, cl ;Forget to include a filename?
- jne @@L0 ;Get one
- mov ds, ax
- @@La:
- mov dx, OFFSET fName
- call GetFileName
- jnz @@Lb
- call Beep
- jmp @@La
- @@Lb:
- jmp SHORT InitFile
- @@L0:
- mov al, ' ' ;Skip leading blanks
- @@L1:
- inc si
- cmp al, [si]
- loope @@L1
- inc cx
- mov di, OFFSET fName ;Move command tail to FName
- rep movsb
- sub al, al ;Make ASCIIZ string
- stosb
- mov ax, 2523h ;Redirect Ctrl C handler
- mov dx, SEG Cancel
- mov ds, dx
- mov dx, OFFSET Cancel
- int 21h
- mov ah, 0Fh ;Get display segment
- int 10h
- mov bx, 0B000h ;B000h for video mode 7 (= MDA or Herc)
- cmp al, 7
- je @@L2
- mov bx, 0B800h ;B800h for the rest
- @@L2:
- mov [cs:videoSegment], bx
- InitFile:
- mov ax, cs ;Compute starting segment of heap
- mov ds, ax
- add ax, 1000h
- mov [heapStart], ax
- mov dx, OFFSET fName ;Open file and set up list of line pointers
- call OpenFile
-
- NextKey:
- call Redraw ;Redraw screen, status line
- NextNoRedraw:
- call DrawCursor ;Place cursor
- sub ah, ah ;Get keypress to AL
- int 16h
- or al, al ;Check for control codes
- je IsAux
- cmp al, ' '
- jl IsCtrl
- call Insert ;Insert or overwrite if none
- jmp NextKey
-
- IsAux:
- xchg al, ah ;Get aux code
- cmp al, 132
- ja NextKey
- mov si, OFFSET auxTable ;Jump indirect to appropriate routine
- DoTableJump:
- shl ax, 1
- add si, ax
- call [WORD si]
- jmp NextKey
-
- IsCtrl:
- mov si, OFFSET ctrlTable ;Jump to routine through table
- sub ah, ah
- jmp DoTableJump
-
- OtherFile:
- ;Close current file and open another
- mov dx, OFFSET fName ;Prompt for new file name
- call GetFileName
- jz Ret0 ;Abort if null string
- test [newFile?], -1 ;If previous file was old file or was changed,
- jnz @@L1
- test [changed?], -1
- jz @@L2
- @@L1:
- call Save ;Save file and close it, then open new one ...
- mov bx, [fHandle]
- mov ah, 3Eh
- int 21h
- @@L2:
-
- OpenFile:
- ;Open file, load if found. Call with dx -> ASCIIZ file name.
- mov [newFile?], 0
- mov [changed?], 0
- mov ax, [heapStart]
- mov [heapPtr], ax
- mov ax, 3D02h ;Try to open file
- int 21h
- jnc OldFile
- mov [newFile?], -1 ;If no such file, set newFile? flag
- mov bx, OFFSET linePtrs ;Set up new file as single blank line
- mov [lastLine], bx
- call NewFile
- jmp XOpenFile
- OldFile:
- mov [fHandle], ax ;Else save file handle
- mov bx, OFFSET linePtrs ;Read file in
- mov dx, [fHandle]
- call ReadFile
- dec bx
- dec bx
- mov [lastLine], bx ;Save index of last line
- XOpenFile:
- mov bx, OFFSET linePtrs ;Reset row, screen, buffer pointers
- mov [top], bx
- mov es, [bx]
- sub di, di
- mov ax, OFFSET blockPtrs
- mov [blockPtrsLast], ax
- Ret0:
- ret
-
- GetFileName:
- ;Prompt for file name. Abort if null name. Call with buffer address in DX.
- push si
- push dx
- mov si, OFFSET newFileMsg ;Print prompt
- call Prompt
- pop dx
- call GetString ;Get file name
- mov si, dx ;Convert to ASCIIZ
- add si, ax
- mov [BYTE si], 0
- @@Lx:
- pop si
- Ret5:
- ret
-
- GetString:
- ;Get string to [DX], return count (minus CR/LF) in AX. Abort if null string.
- push bx
- push cx
- push si
- push di
- push es
- push dx
- mov dx, OFFSET pad ;Get string
- mov ah, 3Fh
- sub bx, bx
- mov cx, 20
- int 21h
- dec ax ;Strip CR/LF
- dec ax
- jz @@La ;Abort if null string
- mov cx, ax ;Copy temporary copy of string to [DX]
- pop dx
- push ax
- mov ax, ds
- mov es, ax
- mov si, OFFSET pad
- mov di, dx
- rep movsb
- pop ax
- pop es
- pop di
- pop si
- pop cx
- pop bx
- ret
- @@La:
- mov si, OFFSET cancelledMsg ;Abort if null string
- jmp Abort
-
- ReadFile:
- ;Load file with handle in DX into memory, assigning segment pointers from BX
- push es
- mov ax, [heapPtr]
- mov es, ax
- sub cx, cx
- sub di, di
- FillBuffer:
- push bx ; Fill buffer
- push cx
- push dx
- mov bx, dx
- mov ah, 3Fh
- mov cx, BUFFERLENGTH
- mov dx, OFFSET buffer
- int 21h
- jnc @@L1 ; Check for read error
- jmp ReadError
- @@L1:
- pop dx
- pop cx
- pop bx
- mov si, OFFSET buffer ; Set pointers
- add ax, si
- mov [bufferPtr], ax
- cmp ax, OFFSET buffer ;Exit if empty buffer
- je EndOfFile
- NextLine:
- mov al, [si] ;Get next char
- cmp al, CR ;If char is CR, end of line
- jne @@L2
- inc si ; move past CR
- cmp [byte si], LF ; and LF if present
- jne @@L1
- inc si
- @@L1:
- call EndOfLine ; pad out line with spaces and save it
- jmp SHORT @@L3
- @@L2:
- movsb ;Else add char to line
- dec cx
- @@L3:
- cmp si, [bufferPtr] ;Loop until end of buffer
- jb NextLine
- cmp si, OFFSET bufferEnd ;If buffer less than full, indicates end of file
- jae FillBuffer
- EndOfFile:
- or di, di ;Finish up present line if anything is on it
- je @@L1
- call EndOfLine
- @@L1:
- mov [heapPtr], es ;Update pointer to start of free heap space
- pop es
- ret
-
- EndOfLine:
- add cx, LINELENGTH ;Pad to end with spaces
- jle @@L1 ;Truncate lines longer than 80 chars
- mov al, ' '
- rep stosb
- @@L1:
- mov [bx], es ;Store segment of this line
- mov ax, es ;Next line
- add ax, 5
- cmp ax, 0A000h ;Out of room?
- jae SHORT TooBig
- mov es, ax
- inc bx
- inc bx
- sub di, di
- sub cx, cx
- Ret3:
- ret
- TooBig:
- mov si, OFFSET noRoomMsg
- jmp Abort
-
- Redraw:
- ;Redraw screen and status line
- mov [here], bx
- mov [hereCol], di
- push bx
- push di
- push ds
- push es
- push di
- mov es, [videoSegment] ;Get segment for display
- mov si, OFFSET editingMsg ;Refresh status line: "Editing ..."
- call Prompt
- mov di, 34 ;Tab to column 17
- mov si, OFFSET fName ; <file name>
- mov ah, ATTRIB_INV
- @@S1:
- lodsb
- or al, al
- je @@S2
- stosw
- jmp @@S1
- @@S2:
- add di, 6 ;3 spaces
- mov al, 'L' ;"L" <line #>
- stosw
- inc di
- inc di
- mov ax, bx
- sub ax, OFFSET linePtrs
- shr ax, 1
- inc ax
- call PrintInt
- add di, 4 ;2 spaces
- mov al, 'C' ;"C" <column number>
- mov ah, ATTRIB_INV
- stosw
- inc di
- inc di
- pop ax ;Get copy of DI as cursor row
- inc ax
- call PrintInt
- mov di, 152 ;Tab to column 76
- mov al, 'I' ;Insert/Overwrite status
- mov ah, ATTRIB_INV
- test [inserting?], -1
- jne @@S3
- mov al, 'O'
- @@S3:
- stosw
- mov al, 'C' ;Changed status
- test [changed?], -1
- jne @@S5
- mov al, ' '
- @@S5:
- stosw
- mov al, 'A'
- test [autoIndent?], -1
- jne @@S6
- mov al, ' '
- @@S6:
- stosw
- mov di, 160 ;Move to next display line
- mov ax, [top] ;Compute bottom of screen
- mov bx, ax
- add ax, (SCREENLENGTH - 1) * 2
- cmp ax, [lastLine] ;If at end of file,
- jle @@L0
- mov ax, [lastLine] ; stop at lastLine
- @@L0:
- mov [bottom], ax
- @@L1: ;For each row
- mov cx, 80 ;Count of chars per row
- mov ds, [cs:bx] ;Get pointer to screen line
- sub si, si ;Initialize column counter
- mov ah, ATTRIB_NL ;Attribute = inverse video if Marked
- test [cs:marking?], -1
- je @@L2
- cmp bx, [cs:mark]
- je @@L1b
- jb @@L1a
- cmp bx, [cs:here]
- jbe @@L1b
- jmp SHORT @@L2
- @@L1a:
- cmp bx, [cs:here]
- jb @@L2
- @@L1b:
- mov ah, ATTRIB_INV
- @@L2: ;For each char, write char and attribute
- lodsb
- stosw
- loop @@L2 ;Next char
- inc bx ;Next row
- inc bx
- cmp bx, [cs:bottom] ;Stop if screen full
- jle @@L1
- mov cx, 160*(SCREENLENGTH+1) ;Fill out screen with blanks
- sub cx, di
- shr cx, 1
- mov ah, ATTRIB_NL
- mov al, ' '
- rep stosw
- @@L3:
- pop es
- pop ds
- pop di
- pop bx
- ret
-
- DrawCursor:
- ;Set cursor shape and place it on screen
- push bx
- mov cl, 13 ;Set cursor shape depending on Inserting?
- mov ch, 12 ;Line for insert mode,
- test [Inserting?], -1
- jne @@L1
- sub ch, ch ;Block for overwrite
- @@L1:
- mov ah, 1
- int 10h
- sub bx, [top] ;Show cursor at current row, column
- shr bx, 1
- inc bx
- mov dh, bl
- mov ax, di
- mov dl, al
- mov ah, 2
- mov bh, 0
- int 10h
- pop bx
- ret
-
- Print0:
- call ClearStatus ;Blank status line
- sub di, di ;Starting at beginning of line ...
-
- Print:
- ;Print string pointed to by SI on status line in inverse video, starting at DI
- push es
- mov es, [videoSegment]
- lodsb ;Get count of string to be printed
- mov cl, al
- sub ch, ch
- mov ah, ATTRIB_INV ;Attribute = inverse video
- @@L1:
- lodsb
- stosw
- loop @@L1
- pop es
- ret
-
- ClearStatus:
- ;Inverse-blank status line
- push di
- push es
- mov es, [videoSegment]
- mov ah, ATTRIB_INV
- mov al, ' '
- mov cx, 80
- sub di, di
- rep stosw
- pop es
- pop di
- ret
-
- Cancel:
- ;Ctrl C routine
- mov si, OFFSET ctrlCMsg ;Abort with message ...
-
- Abort:
- ;Print counted string pointed to by SI on status line and abort
- call Print0 ;Print error message ...
-
- na:
- ;Unassigned key or other error. Beep and abort.
- call Beep ;Beep
- mov ax, -2 ;Reset stack pointer to top
- mov sp, ax
- mov bx, [here] ;Retrieve cursor position in case it was trashed
- mov di, [hereCol]
- call DrawCursor
- jmp NextNoRedraw ;Restart main editing loop
-
- Beep:
- mov ah, 2 ;Output a BELL
- mov dl, BELL
- int 21h
- ret
-
- Prompt:
- push di
- call Print0 ;Print string at start of line
- mov dx, di ;Set cursor to end of printed string ...
- shr dl, 1
- sub dh, dh
- pop di
-
- GotoXY:
- ;Position cursor at row, column given by DL, DH
- push bx
- mov ah, 2
- sub bx, bx
- int 10h
- pop bx
- ret
-
- PrintInt:
- ;Print to ES:DI in inverse video the unsigned decimal integer in AX
- sub dx, dx ;Start stack with a null
- push dx
- or ax, ax ;If integer = 0,
- jne @@L0
- push dx ; push another 0 and skip divisions
- jmp SHORT @@L2
- @@L0:
- mov cx, 10 ;Get remainders of successive divisions by 10
- @@L1:
- div cx
- add dl, '0' ;Convert to ASCII
- mov dh, ATTRIB_INV ;Attribute is reverse video
- push dx
- sub dx, dx
- or ax, ax
- jne @@L1
- @@L2:
- pop ax ;Pop and print remainders in reversed order
- @@L3:
- stosw
- pop ax
- or ax, ax
- jne @@L3
- ret
-
- NewLine:
- ;Jump here if cursor row is changed by a command
- mov [justFound?], 0
- NewLine0:
- cmp bx, OFFSET linePtrs ;Check bounds, adjust if necessary
- jge @@L1
- mov bx, OFFSET linePtrs
- @@L1:
- cmp bx, [lastLine]
- jle @@L2
- mov bx, [lastLine]
- @@L2:
- mov ax, [top]
- cmp bx, ax
- jge @@L3
- mov [top], bx
- @@L3:
- add ax, (SCREENLENGTH-1)*2
- cmp bx, ax
- jle @@L4
- mov ax, bx
- sub ax, (SCREENLENGTH-1)*2
- mov [top], ax
- @@L4:
- mov es, [bx] ;Adjust ES to point to new line
- ret
-
- Left:
- or di, di ;If at start of line,
- jne @@L1
- call Up ; move to end of line above
- jmp EndLine
- @@L1:
- dec di ; else just decrement cursor
- CursorMoved:
- mov [justFound?], 0
- ret
-
- Right:
- cmp di, LINELENGTH - 1 ;If at end of line,
- jne @@L1
- sub di, di ; move to start of line below
- jmp Down
- @@L1:
- inc di ; else just increment cursor
- jmp SHORT CursorMoved
-
- LScanE:
- ;Scan left past first non-space or start of line
- mov al, ' '
- mov cx, di
- inc cx
- std
- repe scasb
- cld
- ret
-
- LScanNE:
- ;Scan left past first space or start of line
- mov al, ' '
- mov cx, di
- inc cx
- std
- repne scasb
- cld
- ret
-
- RScanE:
- ;Scan right past first non-space or end of line
- mov al, ' '
- mov cx, LINELENGTH
- sub cx, di
- repe scasb
- ret
-
- RScanNE:
- ;Scan right past first space or end of line
- mov al, ' '
- mov cx, LINELENGTH
- sub cx, di
- repne scasb
- ret
-
- WordLeft:
- ;Move left one word
- or di, di ;Do nothing if at start of line
- je @@Lx
- mov [justFound?], 0
- dec di ;Else starting at char to left,
- call LScanE ; skip spaces until non-space
- inc di
- je @@Lx ; or start of line,
- call LScanNE ; then scan to next space or start of line
- jne @@L1
- inc di
- @@L1:
- inc di
- @@Lx:
- ret
-
- WordRight:
- ;Move right one word
- cmp di, LINELENGTH - 1 ;Do nothing if at end of line
- je @@Lx
- mov [justFound?], 0
- call RScanNE ;Skip non-spaces until space
- jne @@L1 ; or end of line,
- dec di
- call RScanE ; then scan to next non-space or end of line
- @@L1:
- dec di
- @@Lx:
- ret
-
- HomeLine:
- ;Move cursor to column zero
- sub di, di
- mov [justFound?], 0
- ret
-
- EndLine:
- ;Move cursor to end of line
- push cx
- mov [justFound?], 0
- mov di, LINELENGTH - 1 ;Start at end of line
- call LScanE ;Skip all spaces until non-space
- je @@L1 ; or beginning of line
- inc di
- cmp di, LINELENGTH - 1
- je @@L2
- @@L1:
- inc di
- @@L2:
- pop cx
- Ret2:
- ret
-
- Up:
- ;Move cursor up one line
- cmp bx, OFFSET linePtrs ;If at top of file already, do nothing
- je Ret2
- dec bx
- dec bx
- jmp NewLine
-
- Down:
- ;Move cursor down one line
- cmp bx, [lastLine] ;If at last line already, do nothing
- je Ret2
- inc bx
- inc bx
- jmp NewLine
-
- PageUp:
- ;Move cursor up one page
- sub bx, (SCREENLENGTH-1)*2
- jmp NewLine
-
- PageDown:
- ;Move cursor down one page
- add bx, (SCREENLENGTH-1)*2
- jmp NewLine
-
- TopFile:
- ;Move cursor to top of file
- mov bx, OFFSET linePtrs
- mov [top], bx
- call HomeLine
- jmp NewLine
-
- BottomFile:
- ;Move cursor to bottom of file
- mov bx, [lastLine]
- mov es, [bx]
- mov ax, bx
- sub ax, (SCREENLENGTH-1)*2
- cmp ax, OFFSET linePtrs
- ja @@L1
- mov ax, OFFSET linePtrs
- @@L1:
- mov [top], ax
- call EndLine
- jmp NewLine
-
- Tab:
- ;Tab right
- mov [justFound?], 0
- mov ax, di ;Advance di to next tab stop
- mov cl, [tabSize]
- div cl
- sub cl, ah
- sub ch, ch
- add di, cx
- cmp di, LINELENGTH ;If past end of line,
- jl @@L1
- mov di, LINELENGTH - 1 ;Set cursor at end of line
- @@L1:
- ret
-
- ReverseTab:
- ;Tab left
- mov [justFound?], 0
- mov ax, di ;Decrement di to nearest tab stop
- dec al
- div [tabSize]
- mov al, ah
- sub ah, ah
- inc al
- sub di, ax
- jnc @@L1 ;Set to start of line if past start
- sub di, di
- @@L1:
- ret
-
- CRet:
- ;Split line at cursor
- push ds
- push es
- push di
- push es
- call InsertLine ;Start a new line below current one, ->ES:DI
- pop ds ;DS:SI := current cursor position
- pop si
- push di
- mov cx, LINELENGTH ;CX := # chars left on line
- sub cx, si
- je @@L2
- @@L1:
- movsb ;Split line,
- mov [byte si - 1], ' ' ; blank original to end from cursor
- loop @@L1
- @@L2:
- pop di
- pop es
- pop ds
- mov [changed?], -1 ;Mark file as changed
- jmp NewLine
-
- InsertLine:
- ;Insert a new blank line below current one
- mov cx, 1 ;Make room for new entry in linePtr
- call OpenRow
- inc bx
- inc bx
- mov ax, [heapPtr]
- jmp SHORT BlankLine
-
- NewFile:
- ;Set up initial blank line of a new file
- mov ax, [heapStart] ;Set ES and [bx] to available heap
- BlankLine:
- mov [bx], ax
- mov es, ax
- add ax, 5
- mov [heapPtr], ax ;Update heap pointer (segment value only)
- sub di, di ;Blank new line
- mov cx, LINELENGTH
- mov al, ' '
- rep stosb
- sub di, di ;Home cursor on new line
- test [autoIndent?], -1 ; or if in autoindent mode,
- je @@Lx
- cmp bx, OFFSET linePtrs ; and this is not first line in file,
- je @@Lx
- mov es, [bx - 2] ; line up with first char of line above
- call RScanE
- mov es, [bx]
- dec di
- cmp di, LINELENGTH - 1 ; unless above line is blank
- jb @@Lx
- sub di, di
- @@Lx:
- ret
-
- OpenRow:
- ;Open CX lines at BX in linePtrs
- push cx
- push di
- push es
- mov ax, ds ;DS, ES -> data segment (for linePtr)
- mov es, ax
- mov si, [lastLine] ;SI points to last line's segment pointer
- mov di, si ;DI points CX lines beyond that
- add di, cx
- add di, cx
- mov [lastLine], di ;Point lastLine to new last line
- mov cx, si ;Count = # lines from here to end
- sub cx, bx
- shr cx, 1
- inc cx
- std
- rep movsw ;Move array elements up
- cld
- pop es
- pop di
- pop cx
- ret
-
- Backspace:
- ;Delete char to left of cursor
- mov ax, di ;Unless at first character of file,
- add ax, bx
- sub ax, OFFSET linePtrs
- jz Ret1 ; do Left then Delete
- mov [justFound?], 0
- push di
- call Left
- pop ax ;Don't do Join if already at end of line ...
- or ax, ax
- jne Delete0
-
- Delete:
- ;Delete char at cursor
- mov dx, di ;Save cursor column
- cmp [byte ptr es:LINELENGTH-1], ' ' ;If deleting a space at end of line,
- jne Delete0
- call EndLine
- xchg di, dx
- cmp di, dx
- jge Join ; join to line below
- Delete0:
- push di ; else slide text left
- push cx
- push ds
- mov cx, LINELENGTH - 1
- sub cx, di
- mov si, di
- inc si
- mov ax, es
- mov ds, ax
- rep movsb
- mov [BYTE di], ' ' ;Blank last character on line
- pop ds
- pop cx
- pop di
- mov [changed?], -1
- Ret1:
- ret
-
- UndeleteLine:
- mov bp, [delLinePtrsLast] ;Abort if no lines are in buffer
- cmp bp, OFFSET delLinePtrs
- ja @@L0
- jmp Beep
- @@L0:
- dec bp ;Else move pointer to top line of delete buffer
- dec bp
- mov [delLinePtrsLast], bp
- or di, di ;If cursor is at start of line,
- jne @@L1
- mov cx, 1
- call OpenRow ;Start new row below current one
- mov [bx+2], es ;Swap rows to insert undeleted above current
- mov ax, [bp] ;Retrieve and store pointer to undeleted line
- mov [bx], ax
- jmp NewLine
- @@L1:
- mov cx, LINELENGTH ;Cursor not at start of line
- sub cx, di ;Copy popped line over current one
- push di
- push ds
- mov ds, [bp]
- sub si, si
- rep movsb
- pop ds
- pop di
- ret
-
- Join:
- ;Join lower line to current line at cursor
- cmp bx, [lastLine] ;Abort if this is the last line of the file
- je @@Lx
- push di ;Save registers
- push ds
- push di
- push es
- mov es, [bx + 2] ;Get next line's segment
- push es ;Save a copy
- mov dx, di ;Get length of lower line:
- call EndLine ;Find first non-space char from end
- add dx, di ;If concatenated line is too long, abort.
- cmp dx, LINELENGTH
- jbe @@L0
- call Beep
- pop ax
- pop es
- pop di
- pop ds
- pop ax
- jmp Ret1
- @@L0:
- mov cx, di ;Count = lower line length
- sub si, si ;Source = start of lower line
- pop ds
- pop es ;Destination = present cursor location
- pop di
- rep movsb ;Concatenate lines
- pop ds
- inc bx ;Delete lower line
- inc bx
- call DeleteLineNS
- cmp bx, [lastLine]
- je @@L1
- dec bx
- dec bx
- @@L1:
- pop di ;Restore pointers and return
- @@Lx:
- jmp NewLine
-
- Insert:
- ;Insert or overwrite at cursor
- mov [justFound?], 0
- test [inserting?], -1 ;If inserting, open up space for new character
- jz Insert1
- cmp [BYTE es:LINELENGTH - 1], ' ' ; unless line is full (then beep)
- je Insert0
- jmp Beep
- Insert0:
- push ax
- push cx
- push ds
- mov ax, es
- mov ds, ax
- mov si, LINELENGTH - 1
- mov cx, si
- sub cx, di
- mov di, si
- dec si
- std
- rep movsb
- cld
- pop ds
- pop cx
- pop ax
- Insert1:
- stosb ;Add character
- mov [changed?], -1
- cmp di, LINELENGTH ;Don't advance DI if at end of line
- jb @@L1
- dec di
- @@L1:
- ret
-
- DeleteToEOL:
- ;Delete from cursor to end of line
- mov [justFound?], 0
- push bx ;Save regs to return to current cursor position
- push di
- push es
- push [word autoIndent?] ;Turn autoIndent off
- mov [autoIndent?], 0
- call Cret ;Do Enter then delete lower line
- call DeleteLine
- pop [word autoIndent?]
- pop es
- pop di
- pop bx
- jmp NewLine
-
- DeleteLine:
- ;Delete cursor line and append to buffer
- mov bp, [delLinePtrsLast] ;Save segment of current line in delete buffer
- mov [bp], es
- inc bp
- inc bp
- mov [delLinePtrsLast], bp
- DeleteLineNS: ;Enter here if we don't want to save line
- mov di, bx ;Delete line: destination = this line
- mov si, di ;Source = next line
- inc si
- inc si
- mov cx, [lastLine] ;Count = number of lines from here to end
- mov ax, cx
- dec ax
- dec ax
- mov [lastLine], ax
- sub cx, bx
- shr cx, 1
- mov ax, ds ;Move line segment values above cursor down
- mov es, ax
- rep movsw
- mov [changed?], -1
- sub di, di ;Home cursor on new line
- jmp NewLine
-
- DeleteWordL:
- ;Delete left to space or column zero
- mov si, di ;Save cursor column
- call WordLeft ;Tab left one word
- push di
- CloseGap:
- mov cx, LINELENGTH ;Close gap between di and si cursor positions
- sub cx, si
- push ds
- mov ax, es
- mov ds, ax
- rep movsb
- mov cx, LINELENGTH ;Pad end of line with spaces
- sub cx, di
- mov al, ' '
- rep stosb
- mov [changed?], -1
- pop ds
- pop di
- ret
-
- DeleteWordR:
- ;Delete right to space or end of line
- mov si, di ;Save cursor
- push di
- call WordRight ;Tab right one word
- xchg si, di ;Close up space between si and di
- jmp CloseGap
-
- ToggleIns:
- not [inserting?]
- ret
-
- Jump:
- ;Jump to line number n
- mov si, OFFSET gotoMsg
- call Prompt
- call GetInt
- dec ax
- shl ax, 1
- mov bx, ax
- add bx, OFFSET linePtrs
- mov [justFound?], 0
- jmp JL1 ;Jump to address
-
- GetInt:
- ;Get a decimal integer from keyboard to AX. Carry set on improper input.
- ;Abort if null input.
- push bx
- push cx
- push dx
- push si
- mov dx, OFFSET buffer
- call GetString ;Input a string
- mov cx, ax ;Construct integer a digit at a time
- mov si, OFFSET buffer
- sub ax, ax
- mov bh, 10
- @@L1:
- mov bl, [si] ;Get next char
- inc si
- sub bl, '0'
- jc @@Lx ;Exit with carry set if not a digit
- cmp bl, '9'
- cmc
- jc @@Lx
- mul bh ;AX := AX + (new digit - '0')
- add al, bl
- adc ah, 0
- jc @@Lx ;Check for overflow
- loop @@L1 ;Next char
- @@Lx:
- pop si ;Return with int in AX, carry set if error
- pop dx
- pop cx
- pop bx
- ret
- @@La:
- mov si, OFFSET cancelledMsg
- jmp Abort
-
- SetLabel:
- ;Set label 0-9 at current line
- call GetLabel
- mov [si], bx
- ret
-
- GotoLabel:
- ;Goto label 0-9 previously set by SetLabel
- call GetLabel
- cmp [WORD si], 0
- je JLx
- mov bx, [si] ;Retrieve address
- mov [justFound?], 0
- JL1:
- mov ax, bx
- sub ax, 8 ;Make cursor line fifth from top
- cmp ax, OFFSET linePtrs
- jge @@L1
- mov ax, OFFSET linePtrs
- @@L1:
- mov [top], ax
- JLx:
- jmp NewLine0
-
- GetLabel:
- mov si, OFFSET setLabelMsg
- call Prompt
- mov ah, 8 ;Get char from keyboard
- int 21h
- mov dl, al ;Save copy to echo
- sub al, '0' ;Don't accept input if not a digit
- jl GetLabel
- cmp al, 9
- jg GetLabel
- mov ah, 2
- mov cl, al
- int 21h
- mov si, OFFSET LabelTable ;Form index into LabelTable
- shl cl, 1
- sub ch, ch
- add si, cx ;Return address of label storage in SI
- ret
-
- SetTabs:
- ;Set tab width
- mov si, OFFSET setTabsMsg
- call Prompt
- call GetInt
- mov [tabSize], al
- ret
-
- AutoIndent:
- ;Toggle autoindent mode
- not [autoIndent?]
- ret
-
- Kill:
- ;Clear changed? flag so file changes will be discarded on exit
- mov [changed?], 0
- ret
-
- Save:
- ;Write lines to file, renaming old version with .BAK extension
- push dx
- push di
- push es
- push bx
- mov al, [changed?] ;If no changes, done.
- or al, al
- jnz @@L0
- jmp XSave
- @@L0:
- mov al, [newFile?] ;If a new file, create it first
- or al, [isBAKed?] ;If already BAKed up, no .BAK needed
- jnz DoSave
- mov ah, 3Eh ;Else close file
- mov bx, [fHandle]
- int 21h
- mov ax, ds
- mov es, ax
- mov si, OFFSET fName ;Make new ASCIIZ string with .BAK extension
- mov di, OFFSET fNameBAK
- @@L1:
- lodsb
- cmp al, '.'
- je @@L2
- or al, al
- je @@L2
- stosb
- jmp SHORT @@L1
- @@L2:
- mov cx, 4
- mov si, OFFSET BAK
- rep movsb
- mov ah, 41h ;Delete old back-up copy
- mov dx, OFFSET fNameBAK
- int 21h
- mov dx, OFFSET fName ;Rename current file to file.BAK
- mov di, OFFSET fNameBAK
- mov ah, 56h
- int 21h
- DoSave:
- mov ah, 3Ch ;CREATe new file with old name
- sub cx, cx
- mov dx, OFFSET fName
- int 21h
- jc CantOpen
- mov [fHandle], ax
- mov [isBAKed?], -1 ;Set flag so we only make .BAK file once
- mov bx, OFFSET linePtrs ;Write file
- call WriteFile
- XSave:
- pop bx
- pop es
- pop di
- pop dx
- ret
-
- WriteFile:
- ;Write lines out to file starting at BX and ending at [lastLine]
- push es
- push di
- mov di, OFFSET buffer
- @@L1:
- mov si, di ;Preserve file buffer pointer
- mov es, [bx] ;Strip trailing blanks
- mov cx, LINELENGTH
- mov di, LINELENGTH - 1
- mov al, ' '
- std
- repe scasb
- cld
- je @@L1a
- inc cx
- @@L1a:
- mov ax, ds ;Copy line to file buffer
- mov dx, es
- mov es, ax
- mov ds, dx
- mov di, si
- sub si, si
- rep movsb
- mov ax, CRLF ;Stick a CRLF on the end
- stosw
- mov ax, ds
- mov dx, es
- mov es, ax
- mov ds, dx
- cmp di, OFFSET Buffer + BUFFERLENGTH - 80 ;If buffer is almost full,
- jl @@L2
- call WriteBuffer ; write it
- @@L2:
- inc bx ;Next line, loop until all lines are written
- inc bx
- cmp bx, [lastLine]
- jle @@L1
- call WriteBuffer ;Write final partial buffer to file and exit
- pop di
- pop es
- ret
-
- FileError:
- mov si, OFFSET fileErrorMsg
- jmp Abort
- CantOpen:
- mov si, OFFSET cantOpenMsg
- jmp Abort
- NoRoom:
- mov si, OFFSET noRoomMsg
- jmp Abort
- ReadError:
- mov si, OFFSET rdErrorMsg
- jmp Abort
-
- WriteBuffer:
- ;Write text in buffer to disk
- push bx
- mov ah, 40h
- mov bx, [fHandle]
- mov cx, di
- mov dx, OFFSET Buffer
- sub cx, dx
- jz @@L1
- int 21h
- jc FileError
- mov di, OFFSET Buffer
- @@L1:
- pop bx
- ret
-
- Exit:
- call Save ;Save file if changed
- mov cx, 0C0Dh ;Restore standard cursor size
- mov ah, 1
- int 10h
- mov dx, 1800h ;Put cursor at bottom of screen
- sub bh, bh
- mov ah, 2
- int 10h
- mov ax, 4C00h ;Bye!
- int 21h
-
- BeginBlock:
- ;Start marking block for block operation
- mov [marking?], -1
- mov [mark], bx
- ret
-
- Unmark:
- ;Clear marking
- mov [marking?], 0
- ret
-
- InsertBlock:
- ;Insert from buffer or named file
- push bx
- call FileOrBuffer? ;From file or buffer?
- je InsertBuffer
- mov dx, OFFSET fNameBlock ;If file, open it
- mov ax, 3D00h
- int 21h
- jnc @@L1
- jmp CantOpen
- @@L1:
- mov dx, ax ;Load file
- mov bx, OFFSET blockPtrs
- mov di, bx
- call ReadFile
- mov cx, bx
- mov bx, dx ;Close file
- mov ah, 3Eh
- int 21h
- jmp SHORT DoInsert
- InsertBuffer: ;Insert from buffer
- mov bp, [blockPtrsLast] ;Abort if empty
- cmp bp, OFFSET blockPtrs
- jne @@L0
- pop bx
- jmp na
- @@L0:
- test [needCopies?], -1 ;If not just moving lines, need to duplicate
- jz @@L2
- push bx
- push es
- push ds
- mov bx, bp
- mov dx, [heapPtr]
- @@L1:
- dec bx ;Copy contents of buffered lines to new ones
- dec bx
- mov ds, [cs:bx]
- sub si, si
- mov es, dx
- sub di, di
- mov [cs:bx], es
- mov cx, LINELENGTH
- rep movsb
- add dx, 5
- cmp dx, 0A000h
- jb @@L1a
- jmp TooBig
- @@L1a:
- cmp bx, OFFSET blockPtrs
- ja @@L1
- pop ds
- pop es
- pop bx
- mov [heapPtr], dx
- @@L2:
- mov [needCopies?], -1
- mov cx, bp
- DoInsert:
- pop bx
- sub cx, OFFSET blockPtrs ;Get count of lines to move
- shr cx, 1
- call OpenRow ;Open that much room in array of seg pointers
- mov si, OFFSET blockPtrs ;Copy new lines into opening
- mov di, bx
- mov ax, ds
- mov es, ax
- rep movsw
- mov [changed?], -1
- sub di, di
- jmp NewLine
-
- FileOrBuffer?:
- ;Prompt for file name if Shift is down, put it in fNameBlock.
- ;If return with Z set, Shift was up, indicating buffer is to be used.
- call Shifted? ;If shift is down, prompt for file name
- jz Ret4
- mov dx, OFFSET fNameBlock
- call GetFileName
- jnz Ret4 ;If null string returned, abort
- mov si, OFFSET cancelledMsg
- jmp Abort
-
- Shifted?:
- mov ah, 2 ;Get shift key status
- int 16h
- and al, 3
- Ret4:
- ret
-
- EmptyBuffer:
- ;If Shifted, write block buffer to file, else discard
- mov bp, [blockPtrsLast] ;Abort if buffer is empty
- cmp bp, OFFSET blockPtrs
- jne @@L0
- jmp Beep
- @@L0:
- call Shifted? ;If shifted, write to file
- je @@L1
- push bx
- mov dx, OFFSET fNameBlock
- call GetFileName
- mov si, OFFSET blockPtrs
- mov bx, bp
- dec bx
- dec bx
- call WriteBlock
- pop bx
- @@L1:
- mov ax, OFFSET blockPtrs ;Else just reset buffer pointer
- mov [blockPtrsLast], ax
- @@Lx:
- ret
-
- WriteBlock:
- ;Write block to file. SI -> starting seg pointer, BX -> ending seg pointer.
- push [lastLine] ;Copy block buffered lines to file:
- push [fHandle]
- mov ah, 3Ch ;CREATe file
- sub cx, cx
- mov dx, OFFSET fNameBlock
- int 21h
- jnc @@L1
- jmp CantOpen
- @@L1:
- mov [fHandle], ax ;Write it
- mov [lastLine], bx
- mov bx, si
- call WriteFile
- mov bx, [fHandle] ;Close it
- mov ah, 3Eh
- int 21h
- pop [fHandle]
- pop [lastLine]
- ret
-
- Copy:
- ;Copy marked lines, to file if shift is down, otherwise to buffer.
- test [marking?], -1 ;Abort with a beep if not already marking,
- jnz @@L1
- mov si, OFFSET notMarkingMsg
- jmp Abort
- @@L1:
- push bx
- push di
- push es
- mov si, [mark]
- cmp bx, si ;If mark comes after here, exchange
- jae @@L2
- xchg bx, si
- @@L2:
- mov [mark], si ; save in this order for possible delete
- call FileOrBuffer? ;If Shift key was down when command entered,
- je @@L4
- call WriteBlock
- mov di, OFFSET blockPtrs
- jmp @@Lx
- @@L4:
- mov cx, bx ;If no Shift, move marked lines to buffer
- sub cx, si
- shr cx, 1
- inc cx
- mov di, OFFSET blockPtrs
- mov ax, ds
- mov es, ax
- rep movsw
- @@Lx:
- mov [blockPtrsLast], di ;Save pointer to last line
- pop es
- pop di
- pop bx
- mov [marking?], 0
- ret
-
- DeleteBlock:
- ;Do a Copy, then delete copied lines
- call Copy ;Copy block to file or buffer
- mov si, bx ;Close up copied lines:
- inc si ;SI = cursor line + 2
- inc si
- mov di, [mark] ;DI = start of marking
- mov cx, [lastLine] ;CX = number of lines from here to end
- sub cx, bx
- push es
- mov ax, ds
- mov es, ax
- rep movsb
- pop es
- dec di
- dec di
- mov [lastLine], di ;Store index of new last line
- sub di, di ;Point cursor to start of old marked line
- mov bx, [mark]
- mov [needCopies?], 0
- mov [changed?], -1
- jmp NewLine
-
- Find:
- ;Prompt for and find next <string>. If Shifted, reuse last <string>.
- push bx
- push es
- push di
- call Right
- test [autoReplace?], -1 ;If doing replace all, bypass shift check
- js @@L0
- jnz @@L1
- call Shifted? ;If Shifted,
- jnz @@L1
- @@L0:
- mov si, OFFSET findMsg ;Get search string
- mov dx, OFFSET findString
- call GetCountedString
- @@L1:
- mov si, OFFSET findString
- lodsw
- dec al
- mov dl, al
- mov al, ah
- mov cx, LINELENGTH
- sub cx, di
- FindLoop:
- repne scasb ;Scan for first char of Find string
- jne FindNextLine
- push di ;Once found, compare rest of string
- mov dh, cl
- mov cl, dl
- mov si, OFFSET findString + 2
- repe cmpsb
- je Found
- pop di ;Match failed. Scan again for 1st char.
- mov cl, dh
- jmp FindLoop
- FindNextLine:
- inc bx ;Search next line (until EOF)
- inc bx
- mov es, [bx]
- sub di, di
- mov cl, LINELENGTH
- cmp bx, [lastLine]
- jbe FindLoop
- mov si, OFFSET notFoundMsg ;Not found
- test [autoReplace?], -1 ;If doing auto-replace, return
- jz @@L1
- mov [autoReplace?], 0
- pop di
- pop es
- pop bx
- ret
- @@L1:
- call Print0 ;Else restore cursor, abort with error message
- pop di
- pop es
- pop bx
- jmp na
- Found:
- pop di
- dec di
- add sp, 6
- mov [justFound?], -1
- mov ax, bx ;Show found line 5 below top of screen
- jmp JL1
-
- GetCountedString:
- ;Print prompt string at [SI], read counted string into [DX].
- ;Returns count (minus CR/LF) in AL. DX is advanced one to start of string.
- push di
- push dx
- call Prompt ;Display prompt
- pop dx
- mov di, dx
- inc dx
- call GetString ;Get input string
- mov [di], al ;Store count in front of string
- pop di
- ret
-
- Replace:
- push di
- test [autoReplace?], -1 ;If using auto-replace command,
- jz @@L0
- jns @@L2 ;Skip shift check
- mov [autoReplace?], 1
- jmp SHORT @@L1a ;Get replace string if shifted and first pass
- @@L0:
- test [justFound?], -1 ;Beep if not immediately preceded by a Find
- jnz @@L1
- @@LE:
- pop di
- jmp na
- @@L1:
- call Shifted? ;If not Shifted, prompt for replace string
- jnz @@L2
- @@L1a:
- mov si, OFFSET replaceMsg
- mov dx, OFFSET replaceString
- call GetCountedString
- @@L2:
- mov si, OFFSET replaceString
- lodsb
- sub ah, ah
- mov dx, si
- push ax
- push dx
- sub ch, ch ;Compare lengths of find and replace strings
- mov cl, al
- sub cl, [byte findString] ;If replace string is longer,
- je @@L6
- jb @@L4
- xchg dx, di
- call EndLine ; make sure there will be enough room on line
- xchg dx, di
- add dl, cl
- cmp dl, LINELENGTH
- ja @@LE
- @@L3:
- call Insert0 ; then insert extra characters
- loop @@L3
- jmp SHORT @@L6
- @@L4:
- neg cl ;If shorter, delete difference
- @@L5:
- call Delete0
- loop @@L5
- @@L6:
- pop si ;Now copy new string over old
- pop cx
- sub ch, ch
- pop di
- rep movsb
- mov [changed?], -1
- jmp NewLine
-
- AutoReplace:
- ;Find and replace all. If shift not down, prompt for strings.
- push [top]
- push es
- push di
- push bx
- mov [autoReplace?], 1 ;Set flag: 1 = no shift, -1 = shift
- call Shifted?
- jne @@L1
- mov [autoReplace?], -1
- @@L1:
- call Find ;Find/replace until flag reset by not found
- test [autoReplace?], -1
- jz @@Lx
- call Replace
- jmp @@L1
- @@Lx:
- pop bx ;Restore original position
- pop di
- pop es
- pop [top]
- push si
- call ReDraw ;Refresh screen with any changes
- pop si
- push di
- call Print0 ;Show notFoundMsg and exit
- pop di
- jmp NextNoRedraw
-
- Help:
- push es
- push di
- mov es, [videoSegment]
- mov di, 160
- mov si, OFFSET helpMsg
- mov cx, 80 * 24
- mov ah, ATTRIB_NL
- @@L1:
- lodsb
- stosw
- loop @@L1
- mov si, OFFSET endHelpMsg
- call Print0
- sub ah, ah
- int 16h
- pop di
- pop es
- ret
-
- END
-
-